package com.angel.core.aop;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.angel.core.util.StringUtils;
import com.angel.health.SysLog;
import com.angel.health.SysLogWithBLOBs;
import com.angel.provider.sys.SysManagerLogProvider;
import com.angel.provider.sys.impl.SysManagerLogProviderImpl;
import com.google.gson.Gson;

import net.sf.json.JSONObject;

/** 
* @author 作者姓名  cheng
* @version 
* 创建时间：2016年9月20日 下午5:46:48 
* 类说明 
*/
@Aspect
@Component
public class ReqAspect  {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	/** 编码方式 **/
	private String encoding = "UTF-8";
	/** 是否记录请求日志 **/
	private boolean isShowlog = true;
	/** 请求参数验证失败的默认视图 **/
	private String requestValidateFailureDefaultView = "";
	/** 发送异常时跳转的视图 **/
	private String exceptionView;
	private SysManagerLogProvider provider;

	private String requestUrl = null; // 请求地址
	private String userName = null; // 用户名
	private Map<?, ?> inputParamMap = null; // 传入参数
	private Map<String, Object> outputParamMap = null; // 存放输出结果
	private long startTimeMillis = 0; // 开始时间
	private long endTimeMillis = 0; // 结束时间
	private String ip;//ip
	private String hostName;//主机名
	private String method;//请求方式
	private String params;//提交数据
	private String logType;//日志类型
	private String exception;//异常信息
	
	/** 日志接口      **/
	public void setProvider(SysManagerLogProvider provider) {
		this.provider = provider;
	}
	
	/** 当前请求对象 **/
	@Autowired
	private HttpServletRequest request;
	
	/**
	 * 设置参数编码方式
	 * 
	 * @param encoding
	 *            编码方式,默认采用UTF-8
	 */
	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}
	/**
	 * 是否记录请求日志
	 * 
	 * @param isShowlog
	 *            是否记录请求日志
	 */
	public void setShowlog(boolean isShowlog) {
		this.isShowlog = isShowlog;
	}

	/**
	 * 请求参数验证失败的默认视图
	 * 
	 * @param requestValidateFailureDefaultView
	 *            请求参数验证失败的默认视图
	 */
	public void setRequestValidateFailureDefaultView(String requestValidateFailureDefaultView) {
		this.requestValidateFailureDefaultView = requestValidateFailureDefaultView;
	}
	/**
	 * 发送异常时跳转的视图
	 * 
	 * @param exceptionView
	 *            发送异常时跳转的视图
	 */
	public void setExceptionView(String exceptionView) {
		this.exceptionView = exceptionView;
	}
	/**
	 * 
	 * @Title：doBeforeInServiceLayer
	 * @Description: 方法调用前触发 记录开始时间
	 * @author shaojian.yu
	 * @date 2014年11月2日 下午4:45:53
	 * @param joinPoint
	 */
	@Before(value = "execution(* com.angel..*.*(..))")
	public void doBeforeInServiceLayer(JoinPoint joinPoint) {
		startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间
	}

	/**
	 * 
	 * @Title：doAfterInServiceLayer
	 * @Description: 方法调用后触发 记录结束时间
	 * @author shaojian.yu
	 * @date 2014年11月2日 下午4:46:21
	 * @param joinPoint
	 */
	@AfterReturning(value = "execution(* com.angel..*.*(..))" , returning = "result")
	public void doAfterInServiceLayer(JoinPoint joinPoint) {
		endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间
//		this.printOptLog();
	}

	/**
	 * 
	 * @Title：doAround
	 * @Description: 环绕触发
	 * @author shaojian.yu
	 * @date 2014年11月3日 下午1:58:45
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@Around(value = "execution(* com.angel..*.*(..))")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		/**
		 * 1.获取request信息 2.根据request获取session 3.从session中取出登录用户信息
		 */
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();
		// 从session中获取用户信息
		String loginInfo = (String) request.getSession().getAttribute("user");
		if (loginInfo != null && !"".equals(loginInfo)) {
			userName = loginInfo;
		} else {
			userName = "用户未登录";
		}
		// 获取输入参数
		inputParamMap = request.getParameterMap();
		// 获取请求地址
		requestUrl = request.getRequestURI();
		if(!StringUtils.isEmpty(requestUrl)){
			if(requestUrl.startsWith("/app/")){
				logType = "1";
			}else{
				logType = "0";
			}
		}
		//获取ip
		ip = getIpAddr(request);
		//获取操作方式
		method = request.getMethod();
		//获取主机名
		hostName = getHostName(ip);
		// 执行完方法的返回值：调用proceed()方法，就会触发切入点方法执行
		outputParamMap = new HashMap<String, Object>();
		Object result = pjp.proceed();// result的值就是被拦截方法的返回值
		outputParamMap.put("result", result);
		
		return result;
	}
	
	/**
	 * 异常通知
	 * 
	 * @param jp
	 *            连接点
	 * @param e
	 *            异常对象
	 */
	@AfterThrowing(value = "execution(* com.angel..*.*(..))" , throwing = "e")
	public void doThrow(JoinPoint jp , Throwable e) {
		e.printStackTrace();
		logger.error(e.getMessage() , e);
		request.setAttribute("ex" , e);
		exception = e.getMessage();
	}
	
	//获取ip
	public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (!StringUtils.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("X-Forwarded-For");
        if (!StringUtils.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
        // 多次反向代理后会有多个IP值，第一个为真实IP。
        int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        } else {
             return request.getRemoteAddr();
        }
    }
	
	//获取主机名
	public static String getHostName(String ip){  
        InetAddress inet;  
        try {  
            inet = InetAddress.getByName(ip);  
            return inet.getHostName();  
        } catch (UnknownHostException e) {  
            e.printStackTrace();  
        }  
        return "";  
    } 

	/**
	 * 
	 * @Title：printOptLog
	 * @Description: 输出日志
	 * @author shaojian.yu
	 * @date 2014年11月2日 下午4:47:09
	 */
	private void printOptLog() {
		try {
			Gson gson = new Gson(); // 需要用到google的gson解析包
			JSONObject inputParamJsonStr = JSONObject.fromObject(inputParamMap);
			params = inputParamJsonStr.toString();
			JSONObject outPutParamJsonStr = JSONObject.fromObject(outputParamMap);
			String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
			logger.info(optTime+"\ninputParamJsonStr:" +inputParamJsonStr.toString()+"\noutPutParamJsonStr:"+outPutParamJsonStr);
			
			//保存日志到数据库
			SysLogWithBLOBs log = new SysLogWithBLOBs();
			log.setCreateBy(userName);
			log.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(optTime));
			log.setMethod(method);
			log.setRemoteAddr(ip);
			log.setRequestUri(requestUrl);
			log.setType(logType);
			log.setParams(params);
			log.setException(exception);
			log.setHostName(hostName);
			//provider.save(log);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
//		logger.info("\n user：" + userName + "  url：" + requestPath + "; op_time：" + optTime + " pro_time："
//				+ (endTimeMillis - startTimeMillis) + "ms ;" + " param：" + gson.toJson(inputParamMap) + ";"
//				+ "\n result：" + gson.toJson(outputParamMap));
	}
}